#include "Table.h"
#include "Const.h"
#include "Irq.h"
#include "Mutex.h"
#include "Syscall.h"
#include "LibSyscall.h"
#include "utility/Instruction.h"

extern SegmentDescType gdt[GDT_SIZE];
extern GateDescType idt[IDT_SIZE];
static MutexType mutex;

// 设置GDT中的段描述符
void SetGDTSegmentDesc(int index, uint32_t base, uint32_t limit, uint16_t attr)
{
    if (limit > 0xfffff)
    {
        attr |= 0x8000;
        limit /= 0x1000;
    }

    SegmentDescType *segDesc = &gdt[index >> 3];
    segDesc->limitLow = limit & 0xFFFF;
    segDesc->baseLow = base & 0xFFFF;
    segDesc->baseMid = (base >> 16) & 0xFF;
    segDesc->baseHigh = (base >> 24) & 0xFF;
    segDesc->attr = attr | (((limit >> 16) & 0xF) << 8);
}

void SetIDTGateDesc(int index, uint16_t selector, uint32_t offset, uint16_t attr)
{
    GateDescType *gateDesc = &idt[index];
    SetGateDesc(gateDesc, selector, offset, attr);
}

void SetGateDesc(GateDescType *gateDesc, uint16_t selector, uint32_t offset, uint16_t attr)
{
    gateDesc->offsetLow = offset & 0xFFFF;
    gateDesc->gdtSelector = selector;
    gateDesc->attr = attr;
    gateDesc->offsetHigh = (offset >> 16) & 0xFFFF;
}

void InitTable()
{
    InitMutex(&mutex);
    InitGDT();
    InitIDT();
}

/// @brief initialize global description table
void InitGDT()
{
    // 重置之前的参数
    for (int i = 0; i < GDT_SIZE; i++)
    {
        /* code */
        SetGDTSegmentDesc(i * 8, 0, 0, 0);
    }

    // 设置GDT的代码段
    SetGDTSegmentDesc(GDT_CODE_SELECTOR, 0x00000000, 0xFFFFFFFF,
                      SEG_TYPE_CODE | SEG_TYPE_READ_WRITE | SEG_S_NORMAL | SEG_DPL_0 | SEG_P | SEG_D_32 | SEG_G_4KB);
    // 设置数据段
    SetGDTSegmentDesc(GDT_DATA_SELECTOR, 0x00000000, 0xFFFFFFFF,
                      SEG_TYPE_DATA | SEG_TYPE_READ_WRITE | SEG_S_NORMAL | SEG_DPL_0 | SEG_P | SEG_D_32 | SEG_G_4KB);

    SetGateDesc((GateDescType *)(gdt + (GDT_SYSCALL_SELECTOR >> 3)), GDT_CODE_SELECTOR, (uint32_t)HandleSyscallException, GATE_P | GATE_DPL_3 | SEG_TYPE_SYSCALL | SYSCALL_PARAM_COUNT);

    Lgdt((uint32_t)gdt, sizeof(gdt));
}

/// @brief 初始化中断描述符表
void InitIDT()
{
    for (int i = 0; i < IDT_SIZE; i++)
    {
        SetIDTGateDesc(i, GDT_CODE_SELECTOR, (uint32_t)DefaultExceptionHandler, GATE_P | GATE_D_32 | GATE_TYPE_INTERRUPT | GATE_DPL_0);
    }

    SetInterruptionHandler();

    Lidt((uint32_t)idt, sizeof(idt));
}

uint32_t AllocGdtDesc(void)
{
    LockMutex(&mutex);
    for (int i = 1; i < GDT_SIZE; i++)
    {
        SegmentDescType *desc = gdt + i;
        if (desc->attr == 0)
        {
            UnlockMutex(&mutex);
            desc->attr = SEG_P;
            return i * sizeof(SegmentDescType);
        }
    }
    UnlockMutex(&mutex);
    return -1;
}

uint32_t FreeGDTSelector(int selector)
{
    LockMutex(&mutex);
    gdt[selector / sizeof(SegmentDescType)].attr = 0;
    UnlockMutex(&mutex);
}